#version 440
layout(location = 0) in vec2 qt_TexCoord0;
layout(location = 0) out vec4 FragColor;
layout(std140, binding = 0) uniform buf {
    mat4 qt_Matrix;
    float qt_Opacity;
    vec2 size;
    vec4 color;
    vec4 dark;
    vec4 light;
    vec4 radius;
/* property vector4d attrs: Qt.vector4d(control.spread / _min, 
                                        control.angle * 0.017453,
                                        control.pad / _min, 
                                        control.blend / _min); 
*/
    vec4 attrs;
    float style;        // property real style: control.inward
};

/* 
    当 edge0 < edge1：正常渐变 (0 → 1)
    当 edge0 > edge1：反向渐变 (1 → 0)  ---->  反向时 f(x) = smoothstep( 1.0, 0.0, x ); 随x增大 fx减小
    当 edge0 = edge1：阶跃函数
*/

// 根据Style进行选择 然后再进行平滑 这就是ss函数的作用
float ss(in vec2 arg, in float x) {
    vec2 tmp = mix(arg.yx, arg.xy, style);      // 选择器 
    return smoothstep(tmp.x, tmp.y, x);
}

void main() {
    float   _min = min(size.x, size.y), 
            spread = clamp(attrs.x, 1.0 / _min, 1.0), 
            angle = attrs.y,
            padding = attrs.z, 
            blend = attrs.w, 
            _innerpad = mix(0.0, attrs.x / 2.0, style);

    vec2 _rsize = .5 * (size / _min - 1.0);     // 求宽边与短边的差值 * 1/2 

    vec2 uv = (qt_TexCoord0 - 0.5) * size / _min;       // 移动原点

    vec2 temp = mix(radius.xw, radius.yz, step(uv.x, 0.0));
    float rad = mix(temp.x, temp.y, step(uv.y, 0.0));

    // 不除以blend 会导致? 先跳过这里看后面吧
    // 使用QML编写一个调参页面之后知道这个 传入的 blend 参数用于处理 亮暗区域接壤的部分的融合程度 
    // 传入的 blend 越接近1 亮暗部分区分度越高
    // _cblend 因为 size/_min 会大于1, 且与单位向量点乘有可能得到小于0的值(夹角是钝角)
    // angle: Math.atan((height - pad)/(width - pad)) * 57.295 + 180 ---> control.angle * 0.017453, ( *pi/180 ) --> n*pi/180
    // 这个 sin cos 会取到负值 atan( width/height ) 注意这个角度, 具体细节看同目录的.md文件
    // 所以得到了一个从左上角照射到右下角的光线, 根据处理的像素点的UV坐标 
    // vec_light = ( sin(angle), cos(angle) ) = ( -0.399, -0.917 ) 计算dot 得到这个光束投影到 vec_light 的长度 就是 _cblend 
    // ---> 注意是 有向投影 垂直和大于90度都会变为阴影
    float _cblend = dot(uv, normalize(vec2(sin(angle), cos(angle)))) / blend + 0.5;
    // float _cblend = dot(uv, normalize(vec2(sin(angle), cos(angle)))) + 0.5;
    // float _cblend = dot(uv, normalize(vec2(sin(angle), cos(angle)))) / blend;
    spread = clamp(spread, 1.0 / _min, 1.0);
    // rad = min((1.0 - spread - padding) / 2.0, rad);
    // padding = 0;
    rad = min((1.0 - spread - padding) / 2.0, rad);

    // float rdist
    //     = length(max(abs(uv) - 0.5 + rad + spread / 2.0 + padding / 2.0 - _rsize, 0.0)) - rad;

    // 这里的 rdist  应该写成 abs(uv) - 0.5 - _rsize + spread/2.0 + padding/2.0;
    // 很明显 abs(uv) - 0.5 - _rsize 用于SDF判断内外, 此处计算的就是 将外部排除, 正方形内部是SDF外部, 也就是把正方形内部的区域排除
    // 处理之后 光影只跟 padding 和 spread 有关 
    // /2.0 基本上都是给参数分上下(左右)两半

    // 因为使用了 0.5 来作为边界值, 所以需要让变形后的uv (非0~1 或者 -0.5 ~0.5) 减去 _rsize
    // 以下代码才是人能看得懂的代码 异形的uv坐标在减去 _rsize 之后变为了[-0.5, 0.5] 范围内的值
    // rdist = length( abs(uv) - _rsize - ( 0.5 - spread/2.0 - padding/2.0) )
    // 处理后的UV坐标与 a = ( 0.5 - spread/2.0 - padding/2.0) ) 相减 获得当前处理的像素点(abs处理过) 与 ( a, a )相减 在第一象限计算SDF
    // 如此就获得了SDF的值
    // 并且还是用max 将小于0的结果都设置为0 也就是SDF核心概念
    // 这个就是 IQ大佬的 sdBox 改版; 也是使用了转化到第一象限进行半宽半高比较; 注意划分的三个区域 
        // 1. 内部 2. 外部但是在正上方(渲染的点的位置 x < Rect.w 小于宽度) 
        // 3. 在正右方 ( p.y < Rect.h ); 4. 在右上角 ( p.x>Rect.w && p.y > Rect.h ) ---> 一个 max 就能实现
        // 这里的 a 就是 这个矩形的宽高
    float a = ( 0.5 - spread/2.0 - padding/2.0 );
    float rdist = length( max(abs(uv) - _rsize - a, 0.0) );
    // float rdist
    //        = length(max(abs(uv) - 0.5 + spread / 2.0 + padding / 2.0 - _rsize, 0.0));

    vec4 glow = mix(
        // 根据 _cblend 算出该点的亮暗水平, 也就是根据与光的夹角计算出一个颜色 再与 指定的 color 融合
        // todo 探索 _cblend 以及各种变量的取值范围
        mix(dark, light, clamp(_cblend, 0.0, 1.0)), 
        color,
        // 4.0 这个魔法数字到底用来做什么 ---> 大概是限制这个shader画的特效边缘效果的大小
        // _innerPad 要么为0 要么为 spread/2.0
        ss(vec2(0.0, 4.0 / _min), rdist - _innerpad));
    // ss param1 < param2 时是平滑下降 所以在 inward 时才有反向的效果!
    FragColor = glow * ss(vec2(0.0, spread), rdist + _innerpad / 2.0) * qt_Opacity;
}
